from django.http import JsonResponse
from django.views import View
import os
import json
import threading



class DFAFilter(View):
    lock = threading.Lock()

    def __init__(self):
        self.keyword_chains = {}
        self.delimit = '\x00'

    def __new__(cls, *args, **kwargs):
        cls.keyword_chains = {}
        cls.delimit = '\x00'
        return super.__new__(cls, *args, **kwargs)

    def add(self, keyword):
        if not isinstance(keyword, str):
            keyword = keyword.decode('utf-8')
        keyword = keyword.lower()
        chars = keyword.strip()
        if not chars:
            return
        level = self.keyword_chains
        # print(level)
        for i in range(len(chars)):  # 这里的循环是对重复/部分重复的敏感词进行验证，重复部分则不变，不重复部分进行下面的for循环构建新敏感词树
            if chars[i] in level:
                level = level[chars[i]]
            else:
                if not isinstance(level, dict):
                    break
                for j in range(i, len(chars)):   # 这里的循环是给无敏感词树的词构建树
                    level[chars[j]] = {}
                    last_level, last_char = level, chars[j]
                    level = level[chars[j]]  # 此处的level是原level的子对象，能给原level构建二级树，原level对象因为 level = self.keyword_chains，对象被keyword_chains引用，并没有销毁
                last_level[last_char] = {self.delimit: 0}
                break
        if i == len(chars) - 1:   # 这里是给已有的敏感词树加上{'\x00':0}结尾，比如已有"美国人"敏感词树，如果后面出现"美国"敏感词，需补上结尾
            level[self.delimit] = 0

    def parse(self, path):
        with open(path) as f:
            for keyword in f:
                self.add(keyword.strip())

    def filter(self, message):
        if not isinstance(message, str):
            message = message.decode('utf-8')
        message = message.lower().strip()
        ret = []
        start = 0
        messageLength = len(message)
        sensitiveWords = 0
        while start < messageLength:
            level = self.keyword_chains
            step_ins = 0
            for char in message[start:]:
                if char in level:
                    step_ins += 1
                    if self.delimit not in level[char]:
                        level = level[char]
                    else:
                        mret = [message[start:start + step_ins], "flag"]
                        # ret.append(repl * step_ins)
                        ret.append(mret)
                        start += step_ins - 1
                        sensitiveWords += 1
                        break
                else:
                    mret = [message[start]]
                    ret.append(mret)
                    break
            else:
                ret.append([message[start]])
            start += 1

        response_data = {"code": 200, "data": ret, "msg": "success", "messageLength": messageLength, "sensitiveWords": sensitiveWords}
        return response_data


    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with cls.lock:
                cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance



    def post(self, request):
        req = request.body.decode()
        req_dict = json.loads(req)
        message = req_dict.get("message")
        key_path = os.path.dirname(os.path.abspath(__file__))
        key_path = os.path.join(key_path, "keywords")
        gfw = DFAFilter()
        gfw.parse(key_path)
        print('=============')
        return JsonResponse(gfw.filter(message))
